package controllers

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego/orm"
	"github.com/astaxie/beego/validation"
	"github.com/garyburd/redigo/redis" //引入redis包
	"h1/conf"
	"h1/models"
	"h1/vo"
	"io"
	"math/rand"
	"os"
	"reflect"
	"runtime"
	"sort"
	"strconv"
	"sync"
	"time"
)

var (
	myMap = make(map[int]int, 10)
	//声明一个全局的互斥锁
	//lock 是一个全局的互斥锁，
	//sync 是包: synchornized 同步
	//Mutex : 是互斥
	lock sync.Mutex
)

// TestDeviceDataController是map类型的，有两个字段
// 分别是Routerpattern存放路由地址
// 还有个是JSON存放JSON数据的
// post localhost:8080/v1/api/test
// get  localhost:8080/v1/api/test/get
type TestController struct {
	baseController
}

type Person struct {
	name string
	Age  int
}

type People struct {
	name string
	Age  int
}

type MyStruct struct {
	Name  string
	Score int
}

// 结构体
type Point struct {
	x int
	y int
}

// 结构体
type Rect struct {
	leftUp, rightDown Point
}

// 结构体
type Rect2 struct {
	leftUp, rightDown *Point
}

// 1.声明Hero结构体
type Hero struct {
	Name string
	Age  int
}

type Student struct {
	Name string
	Age  int
}

type Monster struct {
	Name string
	Age  int
}

// 2.声明一个Hero结构体切片类型
type HeroSlice []Hero

// 3.实现Interface 接口
func (hs HeroSlice) Len() int {
	return len(hs)
}

// Less方法就是决定你使用什么标准进行排序
// 1. 按Hero的年龄从小到大排序!!
func (hs HeroSlice) Less(i, j int) bool {
	return hs[i].Age < hs[j].Age
	//修改成对Name排序
	//return hs[i].Name < hs[j].Name
}

func (hs HeroSlice) Swap(i, j int) {
	//交换
	// temp := hs[i]
	// hs[i] = hs[j]
	// hs[j] = temp
	//下面的一句话等价于三句话
	hs[i], hs[j] = hs[j], hs[i]
}

func (this *TestController) One() {
	fmt.Println("hello,world!")
}

func (this *TestController) Two() {
	//var result = DataResponse{}
	// 定义验证的结构体
	valid := validation.Validation{}
	// 验证参数
	testParam := vo.TestAddParam{}
	requestBody := this.Ctx.Input.RequestBody
	//请求参数与验证参数进行映射
	_ = json.Unmarshal(requestBody, &testParam)

	str := this.VerifyParas(valid, testParam)
	if str != "" {
		this.Data["json"] = Response(300, "", str)
		this.ServeJSON()
		return
	}

	realSceneId := testParam.RealSceneId
	id := testParam.Id
	sceneId := testParam.SceneId
	version := testParam.Version
	fmt.Println(id, sceneId, realSceneId, version)

	sxc := vo.TestAddParam{Id: id, SceneId: sceneId, RealSceneId: realSceneId, Version: version}
	this.Data["json"] = Response(0, sxc, "成功")
	this.ServeJSON()
	return
}

func (this *TestController) Three() {
	version := models.SceneVersion{}
	result, err := version.GetObjectById(1)
	fmt.Println(err)
	this.Data["json"] = Response(0, result, "成功")
	this.ServeJSON()
	return
}

func (this *TestController) Four() {
	version := models.SceneVersion{}
	versionAll := version.GetVersionAll()
	fmt.Println(versionAll)
	this.Data["json"] = Response(0, versionAll, "成功")
	this.ServeJSON()
	return
}

func (this *TestController) Five() {
	//var result = DataResponse{}
	// 定义验证的结构体
	valid := validation.Validation{}
	// 验证参数
	testParam := vo.TestAddParam{}
	//请求参数与验证参数进行映射
	_ = json.Unmarshal(this.Ctx.Input.RequestBody, &testParam)

	str := this.VerifyParas(valid, testParam)
	if str != "" {
		this.Data["json"] = Response(300, "", str)
		this.ServeJSON()
		return
	}

	version := models.SceneVersion{}
	versionAll := version.Insert()
	this.Data["json"] = Response(0, versionAll, "成功")
	this.ServeJSON()
	return
}

func (this *TestController) Six() {
	//var result = DataResponse{}
	// 定义验证的结构体
	valid := validation.Validation{}
	// 验证参数
	testParam := vo.TestAddParam{}
	//请求参数与验证参数进行映射
	_ = json.Unmarshal(this.Ctx.Input.RequestBody, &testParam)

	str := this.VerifyParas(valid, testParam)
	if str != "" {
		this.Data["json"] = Response(300, "", str)
		this.ServeJSON()
		return
	}

	versionMod := models.SceneVersion{}
	versionMod.SceneId = testParam.SceneId
	versionMod.RealSceneId = testParam.RealSceneId
	versionMod.Version = testParam.Version
	err := versionMod.Insert()
	this.Data["json"] = Response(0, err, "成功")
	this.ServeJSON()
	return
}

// 查全部
func (this *TestController) Seven() {
	version := models.SceneVersion{}
	sceneVersion := version.GetAllSceneVersion()
	this.Data["json"] = Response(0, sceneVersion, "成功")
	this.ServeJSON()
	return
}

func (this *TestController) Eight() {

	version := models.SceneVersion{}
	sceneVersion := version.GetAllSceneVersion()
	this.Data["json"] = Response(0, sceneVersion, "成功")
	this.ServeJSON()
	return
}

// 单条sql查询
func (this *TestController) SelectOne() {
	testParam := vo.TestAddParam{}
	//请求参数与验证参数进行映射
	_ = json.Unmarshal(this.Ctx.Input.RequestBody, &testParam)

	o := orm.NewOrm()
	var sceneVersions []models.SceneVersion
	_, err := o.Raw(`SELECT * from tb_scene_version WHERE id = ?`).SetArgs(testParam.Id).QueryRows(&sceneVersions)
	if err != nil {
		fmt.Println("SetArgs failed, err:", err)
	}
	this.Data["json"] = Response(0, sceneVersions, "成功")
	this.ServeJSON()
	return
}

// JSON序列化
func (this *TestController) JsonSerial() {
	//var result = DataResponse{}
	// 定义验证的结构体
	valid := validation.Validation{}
	// 验证参数
	testParam := vo.TestAddParam{}
	requestBody := this.Ctx.Input.RequestBody
	//请求参数与验证参数进行映射
	_ = json.Unmarshal(requestBody, &testParam)

	str := this.VerifyParas(valid, testParam)
	if str != "" {
		this.Data["json"] = Response(300, "", str)
		this.ServeJSON()
		return
	}

	realSceneId := testParam.RealSceneId
	id := testParam.Id
	sceneId := testParam.SceneId
	version := testParam.Version
	fmt.Println(id, sceneId, realSceneId, version)

	sxc := vo.TestAddParam{Id: id, SceneId: sceneId, RealSceneId: realSceneId, Version: version}

	data, err := json.Marshal(&sxc)
	if err != nil {
		fmt.Println("序列化失败 err=%v", err)
	}
	fmt.Println(data)
	this.Data["json"] = Response(0, data, "成功")
	this.ServeJSON()
	return
}

// Map序列化
func (this *TestController) MapSerial() {
	//定义一个map
	var a map[string]interface{}
	//make适用
	a = make(map[string]interface{})
	a["name"] = "红孩儿"
	a["age"] = "12"
	a["address"] = "五栋"

	data, err := json.Marshal(&a)
	if err != nil {
		fmt.Println("序列化失败 err=%v", err)
	}
	fmt.Println(data)
	this.Data["json"] = Response(0, data, "成功")
	this.ServeJSON()
	return
}

// slice序列化
func (this *TestController) SliceSerial() {
	//定义一个map
	var slice []map[string]interface{}

	var m1 map[string]interface{}
	//make适用
	m1 = make(map[string]interface{})
	m1["name"] = "红孩儿"
	m1["age"] = "12"
	m1["address"] = "五栋"
	slice = append(slice, m1)

	var m2 map[string]interface{}
	//make适用
	m2 = make(map[string]interface{})
	m2["name"] = "红孩儿"
	m2["age"] = "12"
	m2["address"] = [2]string{"舞动", "勿动"}
	slice = append(slice, m2)

	data, err := json.Marshal(&slice)
	if err != nil {
		fmt.Println("序列化失败 err=%v", err)
	}
	fmt.Println(data)
	this.Data["json"] = Response(0, data, "成功")
	this.ServeJSON()
	return
}

// map测试
func (this *TestController) MapTest() {
	fmt.Println("map(string,任意类型)--------------------------------------------------")
	//定义一个map(string,任意类型)
	var m1 map[string]interface{}
	m1 = make(map[string]interface{})
	m1["name"] = "红孩儿"
	m1["age"] = "12"
	m1["address"] = "五栋"
	fmt.Println(m1)

	fmt.Println("map(string,string)--------------------------------------------------")
	//定义一个map(string,string)
	var m2 map[string]string
	m2 = make(map[string]string)
	m2["name"] = "红孩儿"
	m2["age"] = "12"
	m2["address"] = "五栋"
	fmt.Println(m2)

	fmt.Println("map(string,map(string,string))--------------------------------------------------")
	//定义一个map(string,map(string,string))
	m3 := make(map[string]map[string]string)
	m3["e1"] = make(map[string]string, 3)
	m3["e2"] = make(map[string]string, 3)
	m3["e1"]["name"] = "红孩儿"
	m3["e1"]["age"] = "12"
	m3["e1"]["address"] = "五栋"
	m3["e2"]["name"] = "红孩儿"
	m3["e2"]["age"] = "12"
	m3["e2"]["address"] = "五栋"

	fmt.Println(m3)
	fmt.Println(m3["e1"])
	fmt.Println(m3["e1"]["name"])

	fmt.Println("map修改--------------------------------------------------")
	m3["e1"]["name"] = "哈哈"
	m3["e1"]["age"] = "1111"
	m3["e1"]["address"] = "你好"
	fmt.Println(m3)

	fmt.Println("map删除--------------------------------------------------")
	delete(m3, "e1")
	fmt.Println(m3)

	fmt.Println("map遍历--------------------------------------------------")
	m4 := map[string]string{}
	m4["e1"] = "哈哈1"
	m4["e2"] = "哈哈2"
	m4["e3"] = "哈哈3"
	m4["e4"] = "哈哈4"

	for k, v := range m4 {
		fmt.Printf("k=%v,v=%v \n", k, v)
	}

	fmt.Println("map复杂遍历--------------------------------------------------")
	m3["e1"] = make(map[string]string, 3)
	m3["e1"]["name"] = "哈哈"
	m3["e1"]["age"] = "1111"
	m3["e1"]["address"] = "你好"

	for _, v := range m3 {
		for k1, v1 := range v {
			fmt.Printf("k=%v,v=%v \n", k1, v1)
		}
	}

	fmt.Println("map长度 len(map)--------------------------------------------------")
	fmt.Println(len(m3))

	fmt.Println("map排序 --------------------------------------------------")
	m5 := map[int]string{}
	m5[3] = "哈哈3"
	m5[2] = "哈哈2"
	m5[1] = "哈哈1"
	m5[4] = "哈哈4"
	m5[5] = "哈哈5"
	m5[6] = "哈哈6"
	m5[7] = "哈哈7"
	m5[8] = "哈哈8"
	fmt.Println(m5)

	//先把key排序，然后按key排values
	var keys []int
	for k, _ := range m5 {
		keys = append(keys, k)
	}

	//排序
	sort.Ints(keys)
	for k := range keys {
		fmt.Printf("map[%v]=%v \n", k, m5[k])
	}

	fmt.Println("map里的struct--------------------------------------------------")

	/*	data, err := json.Marshal(&slice)
		if err != nil {
			fmt.Println("序列化失败 err=%v", err)
		}
		fmt.Println(data)
		this.Data["json"] = Response(0, data, "成功")
		this.ServeJSON()
		return
	*/
}

// a表示存储单元中的数据，&a表示存储单元的地址
// a存储单元中的数据可以是一个普通数值，也可以是另一个存储单元的地址，比如：a = &b;语句就是将b的存储单元的地址存入a存储单元中。
// *a代表(a中存储的地址)对应的存储单元中的(数据)，也就是访问*a就等于访问b，于是*a提供了(通过a访问b中的数据)

//a表示a对应的存储单元中的数据。
//&a表示a对应的存储单元的地址。
//*a表示：首先，要求a对应的存储单元中的数据一定是另一个存储单元的地址。于是，*a表示另一个存储单元中的数据。

//当a声明的类型是int时，a中存储的是一个整数数值，通过a可以访问（读取或修改）这个数值。
//当a声明的类型是int*时，a中存储的是一个存储单元的地址，而该存储单元中存储的数据是一个整数数值；通过*a可以访问（读取或修改）这个数值。a == &*a 都是该存储单元的地址。
//当a声明的类型是int**时，a中存储的是一个存储单元的地址，而该存储单元中存储的数据是另外一个存储单元的地址，另外这个存储单元中存储的是一个整数数值；通过**a可以访问（读取或修改）这个数值。

// 指针测试
func (this *TestController) PointTest() {
	var a = 10
	var b *int = &a
	//基本类型 &a=地址
	fmt.Println("基本类型 &a=地址---------------------------------------------")
	fmt.Printf("变量的地址: %x\n", &a)
	fmt.Println(b)

	fmt.Println("对象类型 &person=*p---------------------------------------------")
	var p1 Person
	//底层会对 person.Name = "小米" 进行处理， 会加上 (*person)
	p1.name = "小米"
	p1.Age = 18

	//*a表示：
	//首先，要求a对应的存储单元中的数据一定是另一个存储单元的地址
	//于是，*a表示另一个存储单元中的数据
	var p2 *Person = &p1 //是*p2 不是p2, &p1=只能是*表示
	var p3 = &p2         //默认就是*p3
	fmt.Println("&---------------------------------------------------------------")
	fmt.Printf("p1:: %v\n", p1)
	fmt.Printf("p2:: %v\n", p2) // *p2 = p1
	fmt.Printf("p3:: %v\n", p3)
	fmt.Printf("&p1:: %v\n", &p1) //&p1 = *p2 = p1 = 值 (一种指向，一种引用)
	fmt.Printf("&p2:: %v\n", &p2) //& (*p2) = &p1 = 地址
	fmt.Printf("&p3:: %v\n", &p3) //& (*p3) = &p2 = 地址

	fmt.Println("---------------------------------------------------------------")
	fmt.Println(p2.Age)
	fmt.Println((*p2).Age)
	p2.name = "tom~"

	fmt.Printf("p2.name=%v,p1.name = %v\n", p2.name, p1.name)
	fmt.Printf("p2.name=%v,p1.name = %v\n", (*p2).name, p1.name)
}

func (this *TestController) PointTestX() {

	r1 := Rect{
		Point{1, 2},
		Point{3, 4}}

	//r1有四个int, 在内存中是连续分布
	//打印地址
	fmt.Printf("r1.leftUp.x 地址=%p \n r1.leftUp.y 地址=%p \n r1.rightDown.x 地址=%p \n r1.rightDown.y 地址=%p \n",
		&r1.leftUp.x,
		&r1.leftUp.y,
		&r1.rightDown.x,
		&r1.rightDown.y)

	//r2有两个 *Point类型，这个两个*Point类型的本身地址也是连续的，
	//但是他们指向的地址不一定是连续

	r2 := Rect2{
		&Point{10, 20},
		&Point{30, 40}}

	//打印地址
	fmt.Printf("r2.leftUp 本身地址=%p r2.rightDown 本身地址=%p \n",
		&r2.leftUp,
		&r2.rightDown)

	//他们指向的地址不一定是连续...， 这个要看系统在运行时是如何分配
	fmt.Printf("r2.leftUp 指向地址=%p r2.rightDown 指向地址=%p \n",
		r2.leftUp,
		r2.rightDown)

}

// struct---json---map
func (this *TestController) JsonAndMap() {
	ms := MyStruct{Name: "John", Score: 34}

	var myMap map[string]interface{}
	data, _ := json.Marshal(ms)
	err := json.Unmarshal(data, &myMap)
	if err != nil {
		return
	}
	fmt.Println(myMap["Name"])
	fmt.Println(myMap["Score"])
}

// sort
func (this *TestController) SliceSort() {

	fmt.Println("1==============================================")
	into := []int{0, -1, 10, 7, 90}
	sort.Ints(into)
	fmt.Println(into)

	fmt.Println("2==============================================")
	//测试看看我们是否可以对结构体切片进行排序
	var heroes HeroSlice
	for i := 0; i < 10; i++ {
		hero := Hero{
			Name: fmt.Sprintf("英雄|%d", rand.Intn(100)),
			Age:  rand.Intn(100),
		}
		//将 hero append到 heroes切片
		heroes = append(heroes, hero)
	}

	//看看排序前的顺序
	for _, v := range heroes {
		fmt.Println(v)
	}

	//调用sort.Sort
	sort.Sort(heroes)
	fmt.Println("-----------排序后------------")
	//看看排序后的顺序
	for _, v := range heroes {
		fmt.Println(v)
	}

	fmt.Println("3==============================================")
	i := 10
	j := 20
	i, j = j, i
	fmt.Println("i=", i, "j=", j) // i=20 j = 10
}

// 文件操作
func (this *TestController) OperateFile() {
	fmt.Println("0==============================================")
	//打开文件
	//概念说明: file 的叫法
	//1. file 叫 file对象
	//2. file 叫 file指针
	//3. file 叫 file 文件句柄
	file, err := os.Open("d:/test/wFlier.txt")
	if err != nil {
		fmt.Println("open file err=", err)
	}
	//输出下文件，看看文件是什么, 看出file 就是一个指针 *File
	fmt.Printf("file=%v", file)
	//关闭文件
	err = file.Close()
	if err != nil {
		fmt.Println("close file err=", err)
	}
	fmt.Println()
	fmt.Println("1==============================================")
	file, err = os.Open("d:/test/wFlier.txt")
	if err != nil {
		fmt.Println("open file err=", err)
	}
	//当函数退出时，要及时的关闭 file
	defer file.Close() //要及时关闭 file 句柄，否则会有内存泄漏

	// 创建一个 *Reader ，是带缓冲的
	//const (defaultBufSize = 4096  //默认的缓冲区为 4096
	reader := bufio.NewReader(file) //循环的读取文件的内容
	for {
		str, err := reader.ReadString('\n') // 读到一个换行就结束
		if err == io.EOF {                  // io.EOF 表示文件的末尾
			break
		}
		//输出内容
		fmt.Println(str)
	}
	fmt.Println("2==============================================")
	//创建一个新文件，写入内容 5句 "hello, Gardon"
	filePath := "d:/test/wFlier.txt"
	fileA, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Printf("open file err=%v\n", err)
		return
	}
	//及时关闭file句柄
	defer fileA.Close()

	//准备写入5句 "hello, Gardon"
	str := "hello,Garden\r\n" // \r\n 表示换行
	//写入时，使用带缓存的 *Writer
	writer := bufio.NewWriter(fileA)
	for i := 0; i < 5; i++ {
		writer.WriteString(str)
	}
	//输出内容
	fmt.Println(str)
	//因为writer是带缓存，因此在调用WriterString方法时，其实
	//内容是先写入到缓存的,所以需要调用Flush方法，将缓冲的数据
	//真正写入到文件中， 否则文件中会没有数据!!!
	writer.Flush()
	fmt.Println("3==============================================")

	//将d:/flower.jpg 文件拷贝到 e:/abc.jpg

	//调用CopyFile 完成文件拷贝
	srcFile := "d:/test/flower.jpg"
	dstFile := "d:/test/abc.jpg"
	_, err = CopyFile(dstFile, srcFile)
	if err == nil {
		fmt.Printf("拷贝完成\n")
	} else {
		fmt.Printf("拷贝错误 err=%v\n", err)
	}

}

// 接口操作
func (this *TestController) Inter() {
	fmt.Println("0==============================================")
	//测试
	//先创建结构体变量
	computer := models.Computer{}
	phone := models.Phone{}
	camera := models.Camera{}

	//关键点，各自2次
	computer.Working(phone)
	computer.Working(camera)

	fmt.Println("1==============================================")
	var stu models.Stu //结构体变量，实现了 Say() 实现了 AInterface
	var a models.AInterface = stu
	a.Say()

	var i models.Integer = 10
	var b models.AInterface = i
	b.Say() // integer Say i = 10

	//Monster实现了AInterface 和 BInterface
	var monster models.Monster
	var a2 models.AInterface = monster
	var b2 models.BInterface = monster
	a2.Say()
	b2.Hello()

	fmt.Println("2==============================================")
	var stuA models.StuA
	//var aA models.FInterface = stuA
	//aA.test01()  无法在其他类里使用

	var t models.T = stuA //ok
	fmt.Println(t)
	var t2 interface{} = stuA
	var num1 float64 = 8.8
	t2 = num1
	t = num1
	fmt.Println(t2, t)
	fmt.Println("3==============================================")

	//创建一个LittleMonkey 实例
	monkey := models.LittleMonkey{
		Monkey: models.Monkey{
			Name: "悟空",
		},
	}
	//monkey.climbing()
	monkey.Flying()
	monkey.Swimming()
}

// 协程操作
// 因为没有对全局变量 m 加锁，因此会出现资源争夺问题，代码会出现错误，提示concurrent mapwrites
//  解决方案：加入互斥锁
//  我们的数的阶乘很大，结果会越界,可以将求阶乘改成 sum += uint64(i)
func (this *TestController) Cpu() {
	fmt.Println("0==============================================")
	cpuNum := runtime.NumCPU()
	fmt.Println("cpuNum=", cpuNum)
	//可以自己设置使用多个cpu
	runtime.GOMAXPROCS(cpuNum - 1)
	fmt.Println("ok")

	fmt.Println("1==============================================")
	go test() // 开启了一个协程
	for i := 1; i <= 10; i++ {
		fmt.Println(" main() hello,golang" + strconv.Itoa(i))
		time.Sleep(time.Second)
	}

	fmt.Println("2==============================================")
	// 我们这里开启多个协程完成这个任务[200个]
	// n! 放入map
	for i := 1; i <= 20; i++ {
		go test03(i)
	}

	//休眠10秒钟【第二个问题】等待多线程加map
	time.Sleep(time.Second * 5)

	//这里我们输出结果,变量这个结果
	//===多个协程只有一个可以获得锁打印=====
	lock.Lock()
	for i, v := range myMap {
		fmt.Printf("map[%d]=%d\n", i, v)
	}
	lock.Unlock()

	fmt.Println("3==============================================")

}

func (this *TestController) Chan() {
	fmt.Println("0==============================================")

	//创建两个管道
	intChan := make(chan int, 10)
	exitChan := make(chan bool, 1)

	go writeData(intChan)
	go readData(intChan, exitChan)

	//time.Sleep(time.Second * 10)
	for {
		_, ok := <-exitChan
		if !ok {
			break
		}
	}

	fmt.Println("1==============================================")
	go sayHello()
	go testB()

	for i := 0; i < 10; i++ {
		fmt.Println("main() ok=", i)
		time.Sleep(time.Second)
	}
	fmt.Println("3==============================================")
	fmt.Println("4==============================================")
	//传统的方法在遍历管道取数据时，<<如果不关闭会阻塞而导致 deadlock>>
	//使用select可以解决从管道取数据的阻塞问题

	//1.定义一个管道 10个数据int
	intChanX := make(chan int, 10)
	for i := 0; i < 10; i++ {
		intChanX <- i
	}
	//2.定义一个管道 5个数据string
	stringChan := make(chan string, 5)
	for i := 0; i < 5; i++ {
		stringChan <- "hello" + fmt.Sprintf("%d", i)
	}

	//问题，在实际开发中，可能我们不好确定什么关闭该管道.
	//可以使用select 方式可以解决
	for {
		select {
		//注意: 这里，如果intChan一直没有关闭，不会一直阻塞而deadlock
		//，会自动到下一个case匹配
		case v := <-intChanX:
			fmt.Printf("从intChan读取的数据%d\n", v)
			time.Sleep(time.Second)
		case v := <-stringChan:
			fmt.Printf("从stringChan读取的数据%s\n", v)
			time.Sleep(time.Second)
		default:
			fmt.Printf("都取不到了，不玩了, 程序员可以加入逻辑\n")
			time.Sleep(time.Second)
			return
			//break label
		}
	}
}

func (this *TestController) Reflect() {
	fmt.Println("0==============================================")
	//对(基本数据类型、interface{}、reflect.Value)进行反射的基本操作
	//1. 先定义一个int
	var num = 100
	reflectTest01(num)

	//2. 定义一个Student的实例
	stu := Student{
		Name: "tom",
		Age:  20,
	}
	reflectTest02(stu)

	fmt.Println("1==============================================")
	var numA = 10
	reflect01(&numA)
	fmt.Println("num=", numA) // 20

	//你可以这样理解rVal.Elem()
	// num := 9
	// ptr *int = &num
	// num2 := *ptr  //=== 类似 rVal.Elem()

	fmt.Println("3==============================================")
	fmt.Println("4==============================================")
}

func (this *TestController) Redis() {

	// get a connection from the cluster
	conn := conf.GetClusterConnect()
	//conn := conf.GetConnect()
	fmt.Println("0==============================================")
	//通过go 向redis 写入数据和读取数据
	//1. 链接到redis
	//defer conn.Close() //关闭

	//2. 通过go 向redis写入数据 string [key-val]
	r, err := conn.Do("Set", "name", "tomfoolery猫猫")
	if err != nil {
		fmt.Println("set  err=", err)
		return
	}

	//3. 通过go 向redis读取数据 string [key-val]
	r, err = redis.String(conn.Do("Get", "name"))
	if err != nil {
		fmt.Println("set  err=", err)
		return
	}

	//因为返回 r是 interface{}
	//因为 name 对应的值是string ,因此我们需要转换
	//nameString := r.(string)

	fmt.Println("操作ok ", r)

	fmt.Println("1==============================================")
	//2. 通过go 向redis写入数据 string [key-val]
	_, err = conn.Do("HSet", "user01", "name", "john")
	if err != nil {
		fmt.Println("hset  err=", err)
		return
	}

	_, err = conn.Do("HSet", "user01", "age", 18)
	if err != nil {
		fmt.Println("hset  err=", err)
		return
	}

	//3. 通过go 向redis读取数据
	r1, err := redis.String(conn.Do("HGet", "user01", "name"))
	if err != nil {
		fmt.Println("hget  err=", err)
		return
	}

	r2, err := redis.Int(conn.Do("HGet", "user01", "age"))
	if err != nil {
		fmt.Println("hget  err=", err)
		return
	}

	//因为返回 r是 interface{}
	//因为 name 对应的值是string ,因此我们需要转换
	//nameString := r.(string)

	fmt.Printf("操作ok r1=%v r2=%v \n", r1, r2)
	fmt.Println("redis存数组==============================================")
	if err != nil {
		fmt.Println("redis.Dial err=", err)
		return
	}
	defer conn.Close() //关闭..

	//2. 通过go 向redis写入数据 string [key-val]
	_, err = conn.Do("HMSet", "user02", "name", "john", "age", 19)
	if err != nil {
		fmt.Println("HMSet  err=", err)
		return
	}

	//3. 通过go 向redis读取数据
	strings, err := redis.Strings(conn.Do("HMGet", "user02", "name", "age"))
	if err != nil {
		fmt.Println("hget  err=", err)
		return
	}
	for i, v := range strings {
		fmt.Printf("strings[%d]=%s\n", i, v)
	}

	fmt.Println("4==============================================")

}

// 协程
func test() {
	for i := 1; i <= 10; i++ {
		fmt.Println("test () hello,world " + strconv.Itoa(i))
		time.Sleep(time.Second)
	}
}

// 函数
func test01(arr [3]int) {
	arr[0] = 88
}

// 函数
func test02(arr *[3]int) {
	fmt.Printf("arr指针的地址=%p", &arr)
	(*arr)[0] = 88 //!!
}

// test 函数就是计算 n!, 让将这个结果放入到 myMap
func test03(n int) {

	res := 1
	for i := 1; i <= n; i++ {
		res *= i
	}

	//这里我们将 res 放入到myMap
	lock.Lock()    //加锁
	myMap[n] = res //concurrent map writes?
	lock.Unlock()  //解锁
}

// 自己编写一个函数，接收两个文件路径 srcFileName dstFileName
func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {

	srcFile, err := os.Open(srcFileName)
	if err != nil {
		fmt.Printf("open file err=%v\n", err)
	}
	defer srcFile.Close()
	//通过srcfile ,获取到 Reader
	reader := bufio.NewReader(srcFile)

	//打开dstFileName
	dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Printf("open file err=%v\n", err)
		return
	}

	//通过dstFile, 获取到 Writer
	writer := bufio.NewWriter(dstFile)
	defer dstFile.Close()

	return io.Copy(writer, reader)
}

// write Data
func writeData(intChan chan int) {
	for i := 1; i <= 10; i++ {
		//放入数据
		intChan <- i //
		fmt.Println("writeData ", i)
		//time.Sleep(time.Second)
	}
	close(intChan) //关闭
}

// read data
func readData(intChan chan int, exitChan chan bool) {

	for {
		v, ok := <-intChan
		if !ok {
			break
		}
		time.Sleep(time.Second)
		fmt.Printf("readData 读到数据=%v\n", v)
	}
	//readData 读取完数据后，即任务完成
	exitChan <- true
	close(exitChan)

}

// 函数
func sayHello() {
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		fmt.Println("hello,world")
	}
}

// 函数
func testB() {
	//这里我们可以使用defer + recover
	defer func() {
		//捕获test抛出的panic
		if err := recover(); err != nil {
			fmt.Println("test() 发生错误", err)
		}
	}()
	//定义了一个map
	var myMap map[int]string
	myMap[0] = "golang" //error
	fmt.Println(myMap)
}

// 专门演示反射
func reflectTest01(b interface{}) {

	//通过反射获取的传入的变量的 type , kind, 值

	//1. 先获取到 reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType=", rTyp)
	//2. 获取到 reflect.Value
	value := reflect.ValueOf(b)

	n2 := 2 + value.Int()
	n3 := value.Float()
	fmt.Println("n2=", n2)
	fmt.Println("n3=", n3)
	fmt.Printf("value=%v value type=%T\n", value, value)

	fmt.Printf("value 转成 interface{}")
	//下面我们将 value 转成 interface{}
	iV := value.Interface()
	//将 interface{} 通过断言转成需要的类型
	num2 := iV.(int)
	fmt.Println("num2=", num2)
}

// 专门演示反射[对结构体的反射]
func reflectTest02(b interface{}) {
	//通过反射获取的传入的变量的 type , kind, 值

	//1. 先获取到 reflect.Type
	typeOf := reflect.TypeOf(b)
	value := reflect.ValueOf(b)
	fmt.Println("typeOf=", typeOf)
	fmt.Println("value=", value)

	//3. 获取 变量对应的Kind
	kind1 := value.Kind()
	kind2 := typeOf.Kind()
	fmt.Printf("kind =%v kind=%v\n", kind1, kind2)

	//下面我们将 value 转成 interface{}
	iV := value.Interface()
	fmt.Printf("iv=%v iv type=%T \n", iV, iV)

	//将 interface{} 通过断言转成需要的类型
	//这里，我们就简单使用了一带检测的类型断言.
	//同学们可以使用 switch 的断言形式来做的更加的灵活
	stu, ok := iV.(Student)
	if ok {
		fmt.Printf("stu.Name=%v\n", stu.Name)
	}
}

func reflect01(b interface{}) {
	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal kind=%v\n", rVal.Kind())
	//Elem返回 v持有的接口保管的值的Value封装， 或者v持有的指针指向的值的Value封装
	rVal.Elem().SetInt(20)
}
